---
title: 单一职责原则
description: Single Responsibility Principle (SRP)
sidebar_position: 2
---

# 单一职责原则

## 什么是单一职责原则

单一职责原则（Single Responsibility Principle，简称 SRP）是 SOLID 原则中的第一个原则。其英文描述为：**A class or module should have a single responsibility**。它的定义是：**一个类或者模块只负责完成一个职责（或者功能）**。

这个原则主要强调：
- 不要设计大而全的类
- 一个类应该只关注一个功能领域
- 一个类的变化原因应该只有一个

## 从类和模块的维度理解

在理解单一职责原则时，需要注意其描述对象包含两个维度：类（class）和模块（module）。对这两个概念，我们有两种理解方式：

1. 从抽象层面理解：
   - 模块是比类更加抽象的概念
   - 类可以看作是模块的一种具体实现
   - 单一职责原则适用于任何抽象层次的封装

2. 从粒度层面理解：
   - 模块是比类更加粗粒度的代码块
   - 一个模块可能包含多个类
   - 多个类通过协作来实现模块的职责

无论采用哪种理解方式，单一职责原则的核心思想都是一致的：一个代码单元（无论是类还是模块）都应该只负责一个明确的功能领域。

## 如何判断职责是否单一

判断一个类的职责是否足够单一并没有统一的量化标准，这是一个比较主观的判断。但我们可以通过以下几个方面来进行评估：

### 1. 代码特征判断
- 类中的代码行数、函数或属性过多
- 类依赖的其他类过多，或者被其他类过多地依赖
- 私有方法过多
- 难以给类起一个合适的名字
- 类中大量方法都是集中操作某几个属性

### 2. 业务场景判断
不同的应用场景、不同阶段的需求背景、不同的业务层面，对同一个类的职责是否单一，可能会有不同的判定结果。

例如，一个 UserInfo 类：
```java
public class UserInfo {
    private Long userId;
    private String username;
    private String email;
    private String telephone;
    private String provinceOfAddress;
    private String cityOfAddress;
    private String regionOfAddress;
    private String detailedAddress;
    // ...其他属性
}
```

在不同场景下的判断：
- 如果只是展示用户信息，当前设计可能已经满足单一职责
- 如果要支持电商功能，地址信息可能需要独立成 UserAddress 类
- 如果要支持统一账号系统，身份认证信息（email、telephone）可能需要独立成 UserAuth 类

## 实践建议

### 1. 循序渐进的重构
- 先写一个粗粒度的类满足业务需求
- 随着业务发展，如果类变得庞大，再进行拆分
- 持续进行重构，而不是一次性完成

### 2. 参考性能指标
对于没有太多项目经验的开发者，可以参考以下指标：
- 一个类的代码行数最好不超过 200 行
- 函数个数及属性个数都最好不超过 10 个

### 3. 避免过度拆分
过度拆分可能带来新的问题：
- 降低内聚性
- 增加类之间的耦合
- 影响代码的可维护性

## 示例分析

让我们通过一个序列化功能的例子来说明过度拆分的问题：

```java
// 原始设计
public class Serialization {
    private static final String IDENTIFIER = "UEUEUE;";
    private Gson gson = new Gson();

    public String serialize(Map<String, String> object) {
        StringBuilder textBuilder = new StringBuilder();
        textBuilder.append(IDENTIFIER);
        textBuilder.append(gson.toJson(object));
        return textBuilder.toString();
    }

    public Map<String, String> deserialize(String text) {
        if (!text.startsWith(IDENTIFIER)) {
            return Collections.emptyMap();
        }
        String jsonStr = text.substring(IDENTIFIER.length());
        return gson.fromJson(jsonStr, new TypeToken<Map<String, String>>(){}.getType());
    }
}

// 过度拆分的设计
public class Serializer {
    private static final String IDENTIFIER = "UEUEUE;";
    private Gson gson = new Gson();

    public String serialize(Map<String, String> object) {
        StringBuilder textBuilder = new StringBuilder();
        textBuilder.append(IDENTIFIER);
        textBuilder.append(gson.toJson(object));
        return textBuilder.toString();
    }
}

public class Deserializer {
    private static final String IDENTIFIER = "UEUEUE;";
    private Gson gson = new Gson();

    public Map<String, String> deserialize(String text) {
        if (!text.startsWith(IDENTIFIER)) {
            return Collections.emptyMap();
        }
        String jsonStr = text.substring(IDENTIFIER.length());
        return gson.fromJson(jsonStr, new TypeToken<Map<String, String>>(){}.getType());
    }
}
```

过度拆分的问题：
1. 如果修改协议格式，需要同时修改两个类
2. 可能导致序列化和反序列化不匹配
3. 降低了代码的内聚性和可维护性

## 总结

单一职责原则的核心目标是提高代码的：
- 可读性
- 可维护性
- 可复用性
- 可扩展性

在实际应用中要注意：
1. 根据具体业务场景判断职责是否单一
2. 避免过度拆分
3. 在保持代码质量的同时兼顾开发效率
4. 持续重构而不是追求一步到位

记住，单一职责原则不是目的，而是手段。最终目标是写出高质量的代码。
